#include "function.h"
#include "analitza/variables.h"
#include "analitza/analitza.h"
#include "analitza/expression.h"
#include "functionimpl.h"

#include <cmath>

function::function()
	: m_function(0), m_show(true), m_color(Qt::black)
{}

function::function(const QString &name, const Expression& newFunc, const QColor& color)
	: m_function(0), m_show(true), m_color(color), m_name(name)
{
	if(newFunc.isCorrect()) {
		QString firstBVar=newFunc.isLambda() ? newFunc.bvarList()[0] : "x";
		if(firstBVar=="x")
			m_function=new FunctionY(newFunc);
		else if(firstBVar=="y")
			m_function=new FunctionX(newFunc);
		else if(firstBVar=="q")
			m_function=new FunctionPolar(newFunc);
		else
			m_err << "Function type not recognized";
	} else {
		m_err << "The expression is not correct";
        }
}

function::function(const function& f)
	: m_function(0), m_show(f.m_show), m_color(f.m_color), m_name(f.m_name), m_err(f.m_err)
{
	if(f.m_function)
		m_function=f.m_function->copy();
}

function::~function()
{
	if(m_function)
		delete m_function;
}

function function::operator=(const function& f)
{
	if(&f!=this) {
		if(m_function)
			delete m_function;
		
		if(f.m_function) {
			m_function=f.m_function->copy();
			Q_ASSERT(m_function);
		} else
			m_function=0;
		m_show=f.m_show;
		m_color=f.m_color;
		m_name=f.m_name;
		m_err=f.m_err;
	}
	return *this;
}

void function::update_points(const QRect& viewport, unsigned int max_res)
{
	Q_ASSERT(m_function);
	m_function->updatePoints(viewport, max_res);
}

function::Axe function::axeType() const
{
	return m_function->axeType();
}

bool function::isShown() const
{
	return m_show && m_function && m_function->isCorrect();
}

QLineF function::derivative(const QPointF & p) const
{
	Q_ASSERT(m_function);
	return m_function->derivative(p);
}

QStringList function::bvars() const
{
	return m_function->bvarList();
}

Analitza * function::analitza() const
{
	Q_ASSERT(m_function);
	return &m_function->func;
}

const QVector<QPointF>& function::points() const
{
	return m_function->points;
}

QPair< QPointF, QString > function::calc(const QPointF & dp)
{
	Q_ASSERT(m_function);
	return m_function->calc(dp);
}

bool function::isCorrect() const
{
	return m_function && m_err.isEmpty() && m_function->isCorrect();
}

QStringList function::errors() const
{
	QStringList err(m_err);
	if(m_function)
		err += m_function->m_err;
	return err;
}

QString function::toString() const
{
	Q_ASSERT(m_function);
	return m_function->toString();
}

QStringList function::supportedBoundedVars()
{
	QStringList ret;
	ret.append("x");
	ret.append("y");
	ret.append("q");
	return ret;
}

const Expression& function::expression() const
{
        return *analitza()->expression();

}


QList<int> function::jumps() const
{
	return m_function->m_jumps;
}
